package com.ld.poetry.utils;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;

import java.util.Base64;


/**
 * 加密工具类，仅使用了sha256方法
 * created by vital on 2024/10/7 下午12:26
 */
public class HashUtils {

    private static final Logger log = LoggerFactory.getLogger(HashUtils.class);

    // RSA密钥对
    private static PublicKey RSA_PUBLIC_KEY;
    private static PrivateKey RSA_PRIVATE_KEY;


    /**
     * SHA-256加密，返回十六进制字符串
     * @param base 明文字符串
     * @return
     */
    public static String sha256(String base) {
        try {
            // 获取MessageDigest实例，指定SHA-256算法
            MessageDigest digest = MessageDigest.getInstance("SHA-256");

            // 计算哈希值
            byte[] hashBytes = digest.digest(base.getBytes());

            // 将哈希值转换为十六进制字符串
            StringBuilder hexString = new StringBuilder();
            for (byte b : hashBytes) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            log.error("Error!sha256加密错误：{}", e.toString());
        }
        return null;
    }


    /**
     * SHA-512加密，返回十六进制字符串
     * @param base 明文字符串
     * @return
     */
    public static String sha512(String base) {
        try {
            // 获取MessageDigest实例，指定SHA-256算法
            MessageDigest digest = MessageDigest.getInstance("SHA-512");

            // 计算哈希值
            byte[] hashBytes = digest.digest(base.getBytes());

            // 将哈希值转换为十六进制字符串
            StringBuilder hexString = new StringBuilder();
            for (byte b : hashBytes) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            log.error("Error!512加密错误：{}", e.toString());
        }
        return null;
    }

    //RSA 加密

    /**
     * 生成RSA密钥对
     */
    public static void createRSAKey() {
        log.warn("正在重新生成RSA密钥对");
        KeyPairGenerator kpg = null;
        try {
            kpg = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            log.error("Error!RSA加密生成密钥错误{}", e.toString());
            return;
        }
        //生成密钥对
        kpg.initialize(2048); // 密钥长度
        KeyPair kp = kpg.generateKeyPair();
        //保存公钥和私钥
        RSA_PUBLIC_KEY = kp.getPublic();
        RSA_PRIVATE_KEY = kp.getPrivate();
        log.warn("RSA密钥对生成成功");
    }

    /**
     * RSA 解密，返回解密后的字符串，密文为Base64编码
     * @param encryptedText
     * @return
     */
    public static String RSA_decrypt(String encryptedText) {
        if(RSA_PRIVATE_KEY == null){
            log.error("Error!RSA解密错误，未生成密钥对");
            return null;
        }
        // 解密过程
        try {
            Cipher decryptCipher = Cipher.getInstance("RSA");
            decryptCipher.init(Cipher.DECRYPT_MODE, RSA_PRIVATE_KEY);
            //解密数据
            byte[] decryptedBytes = decryptCipher.doFinal(Base64.getDecoder().decode(encryptedText));
            //转换为字符串
            String decryptedText = new String(decryptedBytes, StandardCharsets.UTF_8);
            System.out.println("解密文本: " + decryptedText);
            return decryptedText;
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException |
                 BadPaddingException e) {
            log.error("Error!RSA解密错误{}", e.toString());
            return null;
        }
    }


    /**
     * RSA 加密，返回加密后的字符串，密文为Base64编码
     * @param originalText
     * @return
     */
    public static String RSA_encrypt(String originalText) {
        //System.out.println("需要加密的文本: " + originalText);
        if(RSA_PUBLIC_KEY == null){
            createRSAKey();
            log.error("Error!RSA加密错误，未生成密钥对");
            return null;
        }

        try {
            Cipher encryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            encryptCipher.init(Cipher.ENCRYPT_MODE, RSA_PUBLIC_KEY);
            //加密
            byte[] encryptedBytes = encryptCipher.doFinal(originalText.getBytes(StandardCharsets.UTF_8));
            //转换为Base64编码
            String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
            //System.out.println("加密后的文本: " + encryptedText);

            return encryptedText;
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException |
                 InvalidKeyException e) {
            log.error("Error!RSA加密错误{}", e.toString());
            return null;
        }

    }

    //返回公钥，返回数组，数组0为模数，数组1为指数
    public static String[] getPublicKey() {
        if(RSA_PUBLIC_KEY == null){
            createRSAKey();
        }
        //转换为RSAPublicKey以访问模数和公钥指数
        java.security.interfaces.RSAPublicKey rsaPublicKey = (java.security.interfaces.RSAPublicKey) RSA_PUBLIC_KEY;
        // 提取模数（Modulus）
        BigInteger modulus = rsaPublicKey.getModulus();
        if(modulus == null){
            return null;
        }

        // 提取公钥指数（Public Exponent）
        BigInteger publicExponent = rsaPublicKey.getPublicExponent();
        // 将BigInteger转换为字节数组，
        byte[] modulusBytes = modulus.toByteArray();
        // 使用longValue转为long，避免不必要的补零
        byte[] exponentBytes = BigInteger.valueOf(publicExponent.longValue()).toByteArray();
        // 使用Base64进行编码
        String modulusBase64 = Base64.getEncoder().encodeToString(modulusBytes);
        String exponentBase64 = Base64.getEncoder().encodeToString(exponentBytes);
        return new String[]{modulusBase64,exponentBase64} ;
    }


    //将字节数组转换为十六进制字符串
    private static String bytesToHex(byte[] bytes) {
        StringBuilder stringBuilder = new StringBuilder();
        for (byte b : bytes) {
            stringBuilder.append(String.format("%02x", b));
        }
        return stringBuilder.toString();
    }

    //将字节数组转换为十进制字符串
    public static String bytesToString(byte[] byteArray) {
        // 使用BigInteger处理字节到十进制的转换
        BigInteger bigInt = new BigInteger(1, byteArray); // 第一个参数1表示正数
        return bigInt.toString();
    }


    /**
     * 计算指定文件的 MD5 值。
     *
     * @param filePath 文件路径
     * @return 文件的 MD5 值
     * @throws IOException 如果文件读取失败
     * @throws NoSuchAlgorithmException 如果算法不可用
     */
    public static String calculateFileMd5(String filePath) throws IOException, NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance("MD5");

        try (FileInputStream fis = new FileInputStream(filePath)) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) > 0) {
                digest.update(buffer, 0, len);
            }
        }

        byte[] hashBytes = digest.digest();
        StringBuilder hexString = new StringBuilder();
        for (byte b : hashBytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }


    /**
     * 计算 MultipartFile 的 MD5 值，分块读取，以减少内存消耗。
     *
     * @param multipartFile MultipartFile 对象
     * @return 文件的 MD5 值
     * @throws NoSuchAlgorithmException 如果算法不可用
     * @throws IOException 如果文件读取失败
     */
    public static String calculateFileMd5(MultipartFile multipartFile) throws NoSuchAlgorithmException, IOException {
        // 创建 MessageDigest 对象
        MessageDigest digest = MessageDigest.getInstance("MD5");

        // 读取文件内容并计算哈希值
        try (InputStream inputStream = multipartFile.getInputStream()) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = inputStream.read(buffer)) > 0) {
                // 更新哈希值
                digest.update(buffer, 0, len);
            }
        }

        // 将哈希值转换为十六进制字符串
        byte[] hashBytes = digest.digest();
        StringBuilder hexString = new StringBuilder();
        for (byte b : hashBytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

}


